/* 
 * CnpjValidator.java
 * 
 * Data de criação: 02/04/2010
 * 
 * CORPORATIVO - MTE. 
 *
 */
package br.com.o2solutions.util.validator;

import java.util.ArrayList;
import java.util.List;

import org.springframework.util.Assert;

import br.com.o2solutions.util.exception.validator.CnpjValidatorException;
import br.com.o2solutions.util.lang.StringUtil;

/**
 * Classe responsável por realizar a validacao de um CNPJ.
 * 
 * @author osvaldeir.
 * @since 02/04/2010
 * 
 */
public final class CnpjValidator {
	
	private static List<String> invalidCnpjs = new ArrayList<String>();
	
	static{
		invalidCnpjs.add("00000000000000");
	}

	/**
	 * Construtor
	 */
	private CnpjValidator() {
	}

	/**
	 * Realiza a validacao de um cnpj quanto a validacao do seu valor.
	 * 
	 * @param cnpj
	 * @throws CnpjValidatorException
	 *             Caso o CNPJ for invalido.
	 */
	public static void validate(String cnpj) throws CnpjValidatorException {
		try {
			Assert.hasText(cnpj);
			Assert.state(cnpj.length() >= 14);
			Assert.isTrue(!invalidCnpjs.contains(unmask(cnpj)));
			Assert.state(isValid(unmask(cnpj)));
		} catch (Throwable e) {
			throw new CnpjValidatorException();
		}
	}

	/**
	 * Retira do CNPJ a mascara (caso exista).
	 * 
	 * @param cnpj
	 * @return String
	 */
	public static String unmask(String cnpj) {
		Assert.hasText(cnpj);
		cnpj = StringUtil.deleteAny(cnpj, ".");
		cnpj = StringUtil.deleteAny(cnpj, "/");
		cnpj = StringUtil.deleteAny(cnpj, "-");
		return cnpj;
	}

	/*
	 * Realiza a validacao do CNPJ quanto aos seus digitos verificadores
	 * 
	 * @param cnpj
	 * 
	 * @return boolean
	 */
	private static boolean isValid(String cnpj) {
		int soma = 0, dig;
		String cnpjCalc = cnpj.substring(0, 12);

		if (cnpj.length() != 14)
			return false;

		char[] chr_cnpj = cnpj.toCharArray();

		/* Primeira parte */
		for (int i = 0; i < 4; i++)
			if (chr_cnpj[i] - 48 >= 0 && chr_cnpj[i] - 48 <= 9)
				soma += (chr_cnpj[i] - 48) * (6 - (i + 1));
		for (int i = 0; i < 8; i++)
			if (chr_cnpj[i + 4] - 48 >= 0 && chr_cnpj[i + 4] - 48 <= 9)
				soma += (chr_cnpj[i + 4] - 48) * (10 - (i + 1));
		dig = 11 - (soma % 11);

		cnpjCalc += (dig == 10 || dig == 11) ? "0" : Integer.toString(dig);

		/* Segunda parte */
		soma = 0;
		for (int i = 0; i < 5; i++)
			if (chr_cnpj[i] - 48 >= 0 && chr_cnpj[i] - 48 <= 9)
				soma += (chr_cnpj[i] - 48) * (7 - (i + 1));
		for (int i = 0; i < 8; i++)
			if (chr_cnpj[i + 5] - 48 >= 0 && chr_cnpj[i + 5] - 48 <= 9)
				soma += (chr_cnpj[i + 5] - 48) * (10 - (i + 1));
		dig = 11 - (soma % 11);
		cnpjCalc += (dig == 10 || dig == 11) ? "0" : Integer.toString(dig);
		return cnpj.equals(cnpjCalc);
	}

}
